-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix SeekLowerBound where tree contains keys that are prefixes of each other #39
Conversation
… other. This seems like a trivial case to miss howevere it stemmed from some confusion (on my part) about whether iradix was ever intended to support keys that were prefixes. It's a long story and I don't even recall exactly why I thought this was the case now given that every other operation on iradix supports this and most even include this case in their test examples. We even had it in the README example! But some combination of: - I was working at the time on a related radix tree that did have the assumption of null-terminated keys - hashicorp/go-memdb always null terminates even for simpler string indexes Anyway the fix is simple and the examples now pass. In addition the fuzz test (which explicitly used the null-termination trick to never trigger this assuming it was necessary in general) now passes without null terminating keys every time I've run it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice find!
There are at least a couple of other issues here I'm working on:
I'll update this PR when done. Thanks for the review @ncabatoff! |
iradix_test.go
Outdated
@@ -1725,17 +1750,15 @@ func TestIterateLowerBoundFuzz(t *testing.T) { | |||
set := []string{} | |||
|
|||
// This specifies a property where each call adds a new random key to the radix | |||
// tree (with a null byte appended since our tree doesn't support one key | |||
// being a prefix of another and treats null bytes specially). | |||
// tree. | |||
// | |||
// It also maintains a plain sorted list of the same set of keys and asserts | |||
// that iterating from some random key to the end using LowerBound produces | |||
// the same list as filtering all sorted keys that are lower. | |||
|
|||
radixAddAndScan := func(newKey, searchKey readableString) []string { | |||
// Append a null byte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the comment also needs to be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh! think it's removed in the second commit 🤦
This seems to fix the issues in buildkit tests moby/buildkit#2182 . Thanks! Does this also close #35 ? |
It should do once I'm done here. Thanks for pointing that out I'd missed it! |
Also adds support for SeekReverseLowerBound to work when keys are prefixes of each other.
I think with the most recent commit this PR now includes:
I'd say I'm reasonably confident that this is now more correct than before. I'd not be super surprised if there are still examples that could be found that cause it to break! The many examples I found manually that our fuzz tests have not yet shows that they are certainly not exhaustive currently. |
I've found another panic while tweaking fuzz tests and ensuring full coverage of example tests for both lower bound methods. I'll add an example and a fix for that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes are looking great!
This also uncovered a couple of bugs: - Fuzz tests would break if empty strings are involved (which are valid) due to erroneously "de-duplicating" them - A panic in SeekLowerBound that only occured in specific tree configurations (fixed)
OK I think those last two commits fix up the remaining issues i've found. I used code coverage reports when running single tests to evaluate the coverage of both the example tests and the fuzz tests to ensure they were exercising every remaining code path in
Thanks for the review @ncabatoff I'll go through your feedback again as I think you had some good points but wanted to get this up today and have this PR in a shape where I think I have some confidence in it's thoroughness again! |
Fuzz tests run 1000 times each locally without a failure after last refactoring:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look great. Thanks for updating ReverseIterator
as well 🎉
Thanks! |
Fixes #37 #28.
This seems like a trivial case to miss however it stemmed from some confusion (on my part) about whether iradix was ever intended to support keys that were prefixes. It's a long story and I don't even recall exactly why I thought this was the case now given that every other operation on iradix supports this and most even include this case in their test examples. We even had it in the README example!
But some combination of:
Anyway the fix is simple and the examples now pass.
In addition the fuzz test (which explicitly used the null-termination trick to never trigger this assuming it was necessary in general) now passes without null terminating keys every time I've run it.